from process.media import *
from common.model import *
from watchdog.events import *
from watchdog.observers import Observer

import logging
import os
import filetype
import datetime
import hashlib
import copy

audio_exts = ["aac", "mid", "mp3", "m4a",
              "ogg", "flac", "wav", "amr", "aiff", "mp4"]


library_conf = LibraryConf(
    basedir="", library_path="", conf_path="", collect_type=0)

library_cache = LibraryCache(songs=[])


def addSong(song: Song):
    """缓存中加入歌曲信息（忽略已有歌曲）"""
    for item in library_cache.songs:
        if item.filepath == song.filepath:
            return
    library_cache.songs.append(song)


def findSongByHashcode(hashcode: str):
    """根据摘要值查找歌曲"""
    for item in library_cache.songs:
        if item.hashcode == hashcode:
            return item


def init(work_folder: str, collect_type: str, audio_pattern: str):
    """初始化音乐资料库"""
    library_conf.basedir = work_folder
    library_conf.library_path = os.path.join(work_folder, "library")
    library_conf.conf_path = os.path.join(work_folder, "conf")
    library_conf.collect_type = int(collect_type)
    library_conf.audio_pattern = audio_pattern

    if os.path.exists(library_conf.library_path) == False:
        os.mkdir(library_conf.library_path)
        logging.debug("目录 %s 已创建" % library_conf.library_path)

    if os.path.exists(library_conf.conf_path) == False:
        os.mkdir(library_conf.conf_path)
        logging.debug("目录 %s 已创建" % library_conf.conf_path)

    observer = Observer()
    event_handler = FileEventHandler()
    observer.schedule(event_handler, library_conf.basedir, True)
    observer.start()

    logging.info("音乐资料库初始化完成")


def scan_music():
    """扫描音乐"""
    logging.info("扫描音乐...")
    library_cache.scaning = True
    __scan(library_conf.basedir)
    logging.info("音乐扫描完成")
    library_cache.scaning = False


def __scan(folder: str):
    logging.debug(f"scaning folder:{folder}")
    files = os.listdir(folder)

    for filename in files:
        sub_filepath = os.path.join(folder, filename)

        if os.path.isdir(sub_filepath):
            __scan(sub_filepath)
        else:
            song = _read_audio_meta(sub_filepath)
            if song is not None:
                collect(library_conf.collect_type, song)
                addSong(song)
                logging.info(f"音频文件: {song.filepath}")


def _read_audio_meta(filepath: str):
    kind = filetype.guess(filepath)
    if kind is not None and audio_exts.__contains__(kind.extension):
        add_time = os.path.getatime(filepath)
        filename = os.path.splitext(os.path.split(filepath)[1])[0]
        song = Song(
            filepath=filepath,
            mime=kind.extension,
            add_time=datetime.datetime.fromtimestamp(
                add_time).__str__(),
            hashcode=__hashstr(filepath),
            title=filename
        )
    else:
        return None

    meta = AudioMediaMeta(filepath)

    song.artist = meta.get_tag(AudioMetaKey.ARTIST)  # 艺术家
    title = meta.get_tag(AudioMetaKey.TITLE)  # 标题
    song.title = song.title if title is None else title
    song.album = meta.get_tag(AudioMetaKey.ALBUM)  # 专辑名
    song.tracknumber = meta.get_tag(AudioMetaKey.TRACKNUMBER)  # 音轨（专辑中第n首歌）
    song.year = meta.get_tag(AudioMetaKey.YEAR)  # 年份
    song.lyrics = meta.get_tag(AudioMetaKey.LYRICS)  # 歌词
    song.picture = meta.get_tag(AudioMetaKey.PICTURE)  # 封面

    song.bitrate = meta.get_bitrate()
    song.frame_rate = meta.get_frame_rate()

    return song


def page_songs(page_index: int, page_size: int):
    """分页获取音乐列表"""
    start = (page_index - 1) * page_size
    end = start + page_size
    new_list = []
    for song in library_cache.songs[start:end]:
        new_song = copy.deepcopy(song)
        new_song.picture = None
        new_list.append(new_song)

    return Page(
        page=page_index,
        page_size=page_size,
        total=library_cache.songs.__len__(),
        list=new_list
    )


def __hashstr(filepath: str):
    with open(filepath, 'rb') as f:
        md5obj = hashlib.md5()
        md5obj.update(f.read())
        hash = md5obj.hexdigest()
        return hash


def collect(type: int, song: Song):
    """资源整理"""

    # 获取新路径
    f1 = "群星" if song.artist is None else song.artist.replace("/", "&")
    f2 = "未命名" if song.album is None else song.album

    if type == 1:
        newpath = os.path.join(library_conf.library_path, f1)
    elif type == 2:
        newpath = os.path.join(library_conf.library_path, f2)
    elif type == 3:
        newpath = os.path.join(library_conf.library_path, f1, f2)
    else:
        newpath = None

    # 路径不同时移动文件
    if newpath is not None and song.filepath != newpath:
        if not os.path.exists(newpath):
            os.makedirs(newpath)
        fn1 = library_conf.audio_pattern.replace(
            "{title}", song.title).replace("{artist}", f1) + "." + song.mime
        destpath = os.path.join(newpath, fn1)
        os.rename(song.filepath, destpath)
        song.filepath = destpath


class FileEventHandler(FileSystemEventHandler):
    def __init__(self):
        FileSystemEventHandler.__init__(self)

    def on_moved(self, event):
        """文件移动事件"""
        if not library_cache.scaning and not event.is_directory:
            song = _read_audio_meta(event.dest_path)
            if song is not None:
                logging.info(
                    f"file {event.src_path} moved to {event.dest_path}")
                # 缓存中存在时更新文件路径
                for current_song in library_cache.songs:
                    if current_song.filepath == event.src_path:
                        current_song.filepath = event.dest_path
                        return
                # 不存在时插入
                addSong(song)

    def on_created(self, event):
        """文件创建事件"""
        if not library_cache.scaning and not event.is_directory:
            song = _read_audio_meta(event.src_path)
            if song is not None:
                # 缓存中存在时更新文件路径
                logging.info(f"file {event.src_path} created")
                for current_song in library_cache.songs:
                    if current_song.filepath == event.src_path:
                        return
                # 不存在时插入
                addSong(song)

    def on_deleted(self, event):
        """文件删除事件"""
        if not library_cache.scaning and not event.is_directory:
            logging.info(f"file {event.src_path} deleted")
            for current_song in library_cache.songs:
                if current_song.filepath == event.src_path:
                    library_cache.songs.remove(current_song)
                    return

    def on_modified(self, event):
        if not library_cache.scaning and not event.is_directory:
            song = _read_audio_meta(event.src_path)
            if song is not None:
                # 缓存中存在时更新文件路径
                logging.info(f"file {event.src_path} modified")
                for current_song in library_cache.songs:
                    if current_song.filepath == event.src_path:
                        library_cache.songs.remove(current_song)
                # 不存在时插入
                addSong(song)
